<?xml version="1.0" encoding="UTF-8" ?>
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:model="http://euss.evaluant.com/schemas/GenerationModel.xsd">
<xsl:output method="text"/>	

	<xsl:template match="/">
using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using Evaluant.Uss;
using Evaluant.Uss.ObjectContext;
using Evaluant.Uss.ObjectContext.Descriptors;

    <xsl:apply-templates/>
	
	</xsl:template>

	<xsl:template match="model:Package">

namespace <xsl:value-of select="@name"/>
{
	<xsl:apply-templates select="model:Enumeration" mode="declaration"/>
	<xsl:apply-templates select="model:Interface" mode="declaration"/>
	<xsl:apply-templates select="model:Class" mode="declaration"/>
}
</xsl:template>

<!-- Enumerations -->
	
<xsl:template match="model:Enumeration" mode="declaration">
	public enum <![CDATA[ ]]> <xsl:value-of select="@name"/> 
	{ 
		<xsl:apply-templates select="model:Literal" mode="declaration"/>
	}
</xsl:template>

<xsl:template match="model:Literal" mode="declaration">
	<xsl:value-of select="@name"/><xsl:if test="position() != last()">,
		</xsl:if>
</xsl:template>

<xsl:template match="model:Relationship" mode="is-composition">
  <xsl:choose>
    <xsl:when test="@type = 'composition'">true</xsl:when>
    <xsl:otherwise>false</xsl:otherwise>
  </xsl:choose>
</xsl:template>
  
	<!-- Interfaces -->
<xsl:template match="model:Interface" mode="declaration">
	public partial interface <xsl:value-of select="@name"/>
	{	
		<xsl:apply-templates select="model:Property" mode="interface-property-declaration" />
	}
</xsl:template>

	<!-- Declares the prototype of every properties of a class with 'get/set' accessors. The return type is the corresponding interface of the return type -->
	<xsl:template match="model:Property" mode="interface-property-declaration">
		<xsl:value-of select="@type"/> <![CDATA[ ]]><xsl:value-of select="@name"/> { get; set; }
		</xsl:template>

	<!-- Declares the prototype of every relationship of a class with 'get' accessor -->
	<xsl:template match="model:Relationship" mode="interface-relationship-declaration-to-many">
		IEnumerable&lt;I<xsl:value-of select="model:Child/@name"/>&gt; <![CDATA[ ]]><xsl:value-of select="model:Child/@role"/> { get; }
</xsl:template>

	<xsl:template match="model:Relationship" mode="interface-relationship-declaration-to-one">
		<xsl:choose>
		<xsl:when test="//model:Enumeration/@name = model:Child/@name">
		<xsl:value-of select="model:Child/@name"/> <![CDATA[ ]]><xsl:value-of select="model:Child/@role"/> { get; set; }
		</xsl:when>
		<xsl:otherwise>
		I<xsl:value-of select="model:Child/@name"/> <![CDATA[ ]]><xsl:value-of select="model:Child/@role"/> { get; }
		</xsl:otherwise>
		</xsl:choose>
</xsl:template>

	<!-- Explicit implementation of the business interface -->
	<xsl:template match="model:Relationship" mode="interface-accessor-to-many">
		IEnumerable&lt;I<xsl:value-of select="model:Child/@name"/>&gt; I<xsl:value-of select="model:Parent/@name"/>.<xsl:value-of select="model:Child/@role"/>
		{	                
			get 
			{ 
				foreach(I<xsl:value-of select="model:Child/@name"/> item in <xsl:value-of select="model:Child/@role"/>) 
					yield return item;
			}
		}
	</xsl:template>

	<xsl:template match="model:Relationship" mode="interface-accessor-to-one">
		<xsl:choose>
		<xsl:when test="//model:Enumeration/@name = model:Child/@name" />
		<xsl:otherwise>
		I<xsl:value-of select="model:Child/@name"/> I<xsl:value-of select="model:Parent/@name"/>.<xsl:value-of select="model:Child/@role"/>
		{
			get { return <xsl:value-of select="model:Child/@role"/>; }
		}
		</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<!-- Classes-->

<xsl:template match="model:Class" mode="declaration">

	<!-- this variable is used in XPath for finding relashionship of this class -->
	<xsl:variable name="name">
		<xsl:value-of select="@name"/>
	</xsl:variable>

	<!-- the name of the associated business interface -->
	<xsl:variable name="business-interface">I<xsl:value-of select="@name"/></xsl:variable>

	<!-- For each class a specific interface is generated (business interface) -->	
	public partial interface <xsl:value-of select="$business-interface"/>
	{
		string Id { get; set; }
		<xsl:apply-templates select="model:Property" mode="interface-property-declaration" />
		<xsl:apply-templates select="../model:Relationship[model:Parent/@name = $name and (model:Child/@multiplicity = '*' or model:Child/@multiplicity = '0..*' or model:Child/@multiplicity = '1..*') ]" mode="interface-relationship-declaration-to-many" />
		<xsl:apply-templates select="../model:Relationship[model:Parent/@name = $name and (model:Child/@multiplicity = '1' or model:Child/@multiplicity = '0..1' or model:Child/@multiplicity = '1..1')]" mode="interface-relationship-declaration-to-one" />
	}
	<!-- The interfaces it implements -->
	<xsl:variable name="implement-code"><xsl:if test="@implement">, <xsl:value-of select="@implement"/></xsl:if></xsl:variable>
	<xsl:variable name="implement"><xsl:value-of select="@implement"/></xsl:variable>
	<!-- The classes it derives from -->
	<xsl:variable name="inherit-code"><xsl:if test="@inherit"><xsl:value-of select="@inherit"/>,</xsl:if></xsl:variable>
	<xsl:variable name="inherit"><xsl:value-of select="@inherit"/></xsl:variable>
  
  [Serializable]
  public partial class <xsl:value-of select="@name"/>Collection : IPersistableCollection&lt;<xsl:value-of select="@name"/>&gt;
	{
		public <xsl:value-of select="@name"/>Collection() : base()
    {
    }

    public <xsl:value-of select="@name"/>Collection (ObjectContext persistenceManager, IPersistable parent, string role, IEnumerable&lt;<xsl:value-of select="@name"/>&gt; data): base(persistenceManager, parent, role, data)
    {
    }
	}

	[Serializable]
	public partial class <xsl:value-of select="@name"/> : <xsl:value-of select="$inherit-code" /> IPersistable, <xsl:value-of select="$business-interface" /><xsl:value-of select="$implement-code" /> 
	{		
	<xsl:if test = "not(@inherit)">
		[NonSerialized]
		protected Entity _Entity;
		
		[NonSerialized]
		protected ObjectContext _PersistenceManager;
		
		Entity IPersistable.Entity
		{
			get
			{
				return _Entity;
			}
			set
			{
				_Entity = value;
			}
		}
		
		ObjectContext IPersistable.ObjectContext
		{
			get
			{
				return _PersistenceManager;
			}
			set
			{
				_PersistenceManager = value;
			}
		}
		
		public string Id
		{
			get
			{
				return _Entity.Id;
			}
			set
			{
				_Entity.Id = value;
			}
		}
		
	</xsl:if>
	<xsl:text>
		void IPersistable.TrackChildren()
		{
			// if the object is not tracked there is nothing to do
			if(_PersistenceManager == null)
				return;
	</xsl:text>
	<xsl:apply-templates select="." mode="trackchildren-implementation" />		
	<xsl:text>
		}
		
	</xsl:text>
	<!-- the code for the inner properties -->
	<xsl:apply-templates select="model:Property" mode="property-implementation" />
	<!-- TODO : manage multiple interface implementation here -->
	<!-- the code for the properties from the implemented interface -->
	<xsl:apply-templates select="//model:Interface[@name = $implement]/model:Property" mode="property-implementation" />
	<!-- Relationships accessors including enumerations -->
	<xsl:apply-templates select="//model:Relationship[(model:Parent/@name = $name) and (model:Child/@multiplicity = '*' or model:Child/@multiplicity = '0..*' or model:Child/@multiplicity = '1..*' )]" mode="relationship-implementation-to-many" />
	<xsl:apply-templates select="//model:Relationship[(model:Parent/@name = $name) and (model:Child/@multiplicity = '1' or model:Child/@multiplicity = '0..1' or model:Child/@multiplicity = '1..1')]" mode="relationship-implementation-to-one" />
	<!-- Relationships accessors for explicit implemenation of business interface -->
	<xsl:apply-templates select="//model:Relationship[(model:Parent/@name = $name) and (model:Child/@multiplicity = '*' or model:Child/@multiplicity = '0..*' or model:Child/@multiplicity = '1..*' )]" mode="interface-accessor-to-many" />
	<xsl:apply-templates select="//model:Relationship[(model:Parent/@name = $name) and (model:Child/@multiplicity = '1' or model:Child/@multiplicity = '0..1' or model:Child/@multiplicity = '1..1')]" mode="interface-accessor-to-one" />
	<!-- Constructors -->
		public <xsl:value-of select="@name"/> ()
		{
			
			this._Entity = new Entity(ObjectContext.ConvertNamespaceDomainToEuss(this.GetType().FullName));
		}

		public <xsl:value-of select="@name"/> (Entity e)
		{
			this._Entity = e;
		}

		[Serializable]
		public <xsl:if test="(@inherit)">new </xsl:if>class ParentRelationships
		{
			private IPersistable _Owner;
	
			public ParentRelationships()
			{
			}
			
			public ParentRelationships(IPersistable o)
			{
				_Owner = o;
			}
		<xsl:apply-templates select="//model:Relationship[(model:Child/@name = $name) and (model:Parent/@multiplicity = '*' or model:Parent/@multiplicity = '0..*' or model:Parent/@multiplicity = '1..*' )]" mode="parent-relationship-implementation-to-many" />
		<xsl:apply-templates select="//model:Relationship[(model:Child/@name = $name) and (model:Parent/@multiplicity = '1' or model:Parent/@multiplicity = '0..1' or model:Parent/@multiplicity = '1..1' )]" mode="parent-relationship-implementation-to-one" />
		}
	}
</xsl:template>

	<!-- The code for tracking all related objects. Applied to all inherited classes -->
	<xsl:template match="model:Class" mode="trackchildren-implementation">
		<!-- this variable is used in XPath for finding relashionship of this class -->
		<xsl:variable name="name">
			<xsl:value-of select="@name"/>
		</xsl:variable>
		<xsl:variable name="inherit">
			<xsl:value-of select="@inherit"/>
		</xsl:variable>
		<xsl:apply-templates select="//model:Relationship[model:Parent/@name = $name ]" mode="trackchildren-implementation" />
		<!-- recursive call for adding the implementation to all parent relationships -->
		<xsl:apply-templates select="//model:Class[@name = $inherit]" mode="trackchildren-implementation" />
	</xsl:template>

	<!-- The code for tracking a relationship -->
	<xsl:template match="model:Relationship" mode="trackchildren-implementation">
		<xsl:choose>
		<xsl:when test="//model:Enumeration/@name = model:Child/@name" />
		<xsl:otherwise>
			if(_<xsl:value-of select="model:Child/@role"/> != null)
				_PersistenceManager.TrackObject(_<xsl:value-of select="model:Child/@role"/>);
		</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

	<!-- the implementation of a property to get/set from the Entity -->
	<xsl:template match="model:Property" mode="property-implementation">
    protected <xsl:value-of select="@type"/> _<xsl:value-of select="@name"/>;

    public <xsl:value-of select="@type"/><![CDATA[ ]]><xsl:value-of select="@name"/>
    {
      get
      {
        if(_Entity != null &amp;&amp; !_Entity.IsNull("<xsl:value-of select="@name"/>"))
          _<xsl:value-of select="@name"/> = (<xsl:value-of select="@type"/>)this._Entity["<xsl:value-of select="@name"/>"];
          
        return _<xsl:value-of select="@name"/>;
      }

      set
      {
        _<xsl:value-of select="@name"/> = value;
        if(_Entity != null)
			this._Entity["<xsl:value-of select="@name"/>"] = value;
      }
    }
    <xsl:apply-templates/>	
	</xsl:template>

	<!-- the implementation of a relationship accessors-->
	<xsl:template match="model:Relationship" mode="relationship-implementation-to-many">
    protected <xsl:value-of select="model:Child/@name"/>Collection _<xsl:value-of select="model:Child/@role"/>;

    [PersistentProperty("_<xsl:value-of select="model:Child/@role"/>", <xsl:apply-templates select="." mode="is-composition" />)]
    public <xsl:value-of select="model:Child/@name"/>Collection <xsl:value-of select="model:Child/@role"/>
    {
      get
      {
        if(_<xsl:value-of select="model:Child/@role"/> == null)
        {
          // Inferred relationships
          EntitySet entities = _Entity.GetEntitySet("<xsl:value-of select="model:Child/@role"/>");
          List&lt;<xsl:value-of select="model:Child/@name"/>&gt; items = entities.Count == 0 ? null : _PersistenceManager.LoadWithEntities&lt;<xsl:value-of select="model:Child/@name"/>&gt;(entities);

          _<xsl:value-of select="model:Child/@role"/> = new <xsl:value-of select="model:Child/@name"/>Collection(_PersistenceManager, this, "<xsl:value-of select="model:Child/@role"/>", items);
        }
        return _<xsl:value-of select="model:Child/@role"/>;
      }

      set // Defined for Serializable() compatibility only
      {
        _<xsl:value-of select="model:Child/@role"/> = value;
      }
    }
</xsl:template>

	<!-- the implementation of a relationship accessors-->
	<xsl:template match="model:Relationship" mode="relationship-implementation-to-one">
		<xsl:choose>
			<xsl:when test="//model:Enumeration/@name = model:Child/@name">
    protected <xsl:value-of select="model:Child/@name"/> <![CDATA[ ]]> _<xsl:value-of select="model:Child/@role"/>;

      [PersistentProperty("_<xsl:value-of select="model:Child/@role"/>", <xsl:apply-templates select="." mode="is-composition" />)]
      public <xsl:value-of select="model:Child/@name"/> <![CDATA[ ]]> <xsl:value-of select="model:Child/@role"/>
    {
      get
      {
		    if(_Entity != null)
		    {
			    if(_Entity.IsNull("<xsl:value-of select="model:Child/@role"/>"))
				    _<xsl:value-of select="model:Child/@role"/> = default(<xsl:value-of select="model:Child/@name"/>);
          else
            _<xsl:value-of select="model:Child/@role"/> = (<xsl:value-of select="model:Child/@name"/>)Enum.Parse(typeof(<xsl:value-of select="model:Child/@name"/>), (string)this._Entity["<xsl:value-of select="model:Child/@role" />"]);
        }

        return _<xsl:value-of select="model:Child/@role"/>;
      }

      set
      {
        _<xsl:value-of select="model:Child/@role"/> = value;
        if(_Entity != null)
            this._Entity["<xsl:value-of select="model:Child/@role" />"] = Enum.GetName(typeof(<xsl:value-of select="model:Child/@name"/>), value);
      }
    }
      </xsl:when>
			<xsl:otherwise>
		
		[NonSerialized]
		private bool _Is<xsl:value-of select="model:Child/@role"/>Loaded = false;

		protected <xsl:value-of select="model:Child/@name"/> _<xsl:value-of select="model:Child/@role"/>;

		public <xsl:value-of select="model:Child/@name"/> <![CDATA[ ]]><xsl:value-of select="model:Child/@role"/>
		{
			get 
			{ 
            if(!_Is<xsl:value-of select="model:Child/@role"/>Loaded &amp;&amp; _PersistenceManager != null &amp;&amp; _Entity != null)
            {
            // Inferred relationships
            Entity entity = _Entity.GetEntity("<xsl:value-of select="model:Child/@role"/>");
            IList items = null;
            if(entity == null)
            {
                if(_Entity.InferredReferences.Contains("<xsl:value-of select="model:Child/@role"/>"))
                    _<xsl:value-of select="model:Child/@role"/> = null;
                else
                    items = _PersistenceManager.LoadReference(_Entity, "<xsl:value-of select="model:Child/@role"/>");
            }
            else
            {
                items = _PersistenceManager.LoadWithEntities&lt;<xsl:value-of select="model:Child/@name"/>&gt;(new EntitySet( new Entity[] { entity }));
            }

            if(items != null &amp;&amp; items.Count > 0)
              _<xsl:value-of select="model:Child/@role"/> = (<xsl:value-of select="model:Child/@name"/>)items[0];

            _Is<xsl:value-of select="model:Child/@role"/>Loaded = true;
        }

        return _<xsl:value-of select="model:Child/@role"/>;
			}			
			set
			{
				// Removes the reference to an existing entity
				if(<xsl:value-of select="model:Child/@role"/> != null &amp;&amp; _Entity != null)
				{
					_Entity.DeleteElement("<xsl:value-of select="model:Child/@role"/>");
				}
				
				// Creates the reference only if it is a concrete entity
				if(value != null &amp;&amp; _Entity != null)
				{
					_Entity.AddValue("<xsl:value-of select="model:Child/@role"/>", ((IPersistable)value).Entity);
				}
				
				_<xsl:value-of select="model:Child/@role"/> = value;
			}
		}			
			</xsl:otherwise>
		</xsl:choose>
	</xsl:template>

</stylesheet>

  
